19.1 布尔表达式

文章目录
  1. 1. 使用 true 和 false 做布尔判断
    1. 1.1. 隐式地比较布尔值,可以使判断语句更清晰
  2. 2. 简化复杂的表达式
    1. 2.1. 判断中项数很多的情况
      1. 2.1.1. 将复杂的表达式拆分
      2. 2.1.2. 将复杂的表达式提取为布尔函数
    2. 2.2. 涉及到多个变量的复杂判断
      1. 2.2.1. 使用决策表来代替复杂的条件
  3. 3. 编写肯定形式的布尔表达式
    1. 3.1. 在 if else 语句中
    2. 3.2. 逆转含义,更换变量的名字
    3. 3.3. 利用狄摩根定理
  4. 4. 用括号使布尔表达式更清晰
    1. 4.1. 使用如下技巧使得括号准确配对
    2. 4.2. 把布尔表达式全部括在括号里面
  5. 5. 理解布尔表达式的求值方式
    1. 5.1. 短路求值
    2. 5.2. 逻辑运算符 & 和 |
    3. 5.3. 例子
  6. 6. 按照数轴的顺序来书写数值表达式
  7. 7. 与 0 比较时的指导原则
  8. 8. 布尔表达式的常见问题
    1. 8.1. 在 C 家族语言中,可以使用把常量放在比较的左端这一技巧
    2. 8.2. 在 C++中,可以考虑创建预处理宏来替换 &&、||、==(不得已才这样做)
    3. 8.3. 在 Java 中,要理解 a==b 和 a.equals(b) 的差异

除了顺序结构外,所有的控制结构都要依赖布尔表达式的求值

使用 true 和 false 做布尔判断

请在布尔表达式的判断里使用 true 和 false 来代表真和假,而不要用 0 和 1 等数值。如果你的语言不直接支持这些写法,那么就用预处理宏或者全局变量来创建它们。

使用 0 和 1等数值的坏处是:降低了可读性,而且意义有时是非常含混的,有时你甚至不能确定它是否是用来做布尔判断的

隐式地比较布尔值,可以使判断语句更清晰

把表达式作为布尔表达式(而不需要“画蛇添足”地再和 true/false 直接比较一次),可以让表达式里的项数更少、可读性更高(更像英语中的对话)

画蛇添足的直接比较:

1
2
if (printerError == False):
pass

隐式比较:

1
2
if (not printerError):
pass

简化复杂的表达式

判断中项数很多的情况

将复杂的表达式拆分

将原来复杂的判断拆分为几个小部分,将每个小部分的判断结果赋给一些新的布尔变量,再用这些新的布尔变量组合成一个较简单的判断

衡量复杂与简单是根据布尔逻辑判断的项数

将复杂的表达式提取为布尔函数

即使这个复杂的判断只用一次,下面的做法也很有必要,因为可以改善可读性,更加集中于对主程序中整体流程的理解。具体是:将这个判断的过程提取到一个命名良好的子程序里,然后在主程序中判断这个子程序的返回值即可。这个子程序的名字也在主程序中引入了一个抽象,成为一种自说明。

toExemplify-book

涉及到多个变量的复杂判断

使用决策表来代替复杂的条件

具体参考 [[表驱动法]]

编写肯定形式的布尔表达式

否定形式的逻辑表达式可能会让人一时转不过弯,转换为肯定形式会更加清晰

在 if else 语句中

可以把判断条件从否定形式转换为肯定形式,并互换 if 和 else 子句中的代码

这条建议可能会和“在 if 子句中先处理高频的情况”(参考[[……]])冲突,可以配合下一条建议(更改名字)使用

逆转含义,更换变量的名字

如将 !statusOK 替换成 errorDetected

利用狄摩根定理

toExemplify-book

用括号使布尔表达式更清晰

使用括号降低了对代码阅读者的要求,不再要求他们对该语言的求值优先级很熟练。对于你来说,如果拿不准优先级,使用括号也是非常好的解决方法

使用如下技巧使得括号准确配对

toExemplify-book

现在一般在编辑器中都有这个功能了

把布尔表达式全部括在括号里面

这样能够改善可读性

理解布尔表达式的求值方式

不同语言下对布尔表达式的求值方式可能不同,尤其是要注意是否采用“短路(short-circuit)”求值(或者称为惰性lazy求值)

短路求值

“短路”and:从左往右继续计算,如果发现有一个操作数(operand)为假,则跳过剩余的计算

“短路”or:从左往右继续计算,如果发现有一个操作数(operand)为真,则跳过剩余的计算

用处是:利用这一性质,恰当书写求值顺序,就可以减少判断语句的书写

逻辑运算符 & 和 |

Java 中的逻辑运算符 &| 会保证,所有的项都会经过完整的求值

例子

toExemplify-book

按照数轴的顺序来书写数值表达式

具体操作是:从左到右、从小到大地排列元素(常量和变量)。这样会很直观地确定变量所需要的范围

如:

1
2
3
MIN_ELEMENTS <= i and i <= Max_ELEMENTS
i < MIN_ELEMENTS
Max_ELEMENTS < i

toExemplify-book-pic

与 0 比较时的指导原则

一句话,当 0 作为布尔变量时,隐式比较;其他情况,显式比较

当 0 作为字符终止符、空指针时,上面的建议虽然有违既成的 C 传统,但随之也带来了可读性的改善

toNote

布尔表达式的常见问题

在 C 家族语言中,可以使用把常量放在比较的左端这一技巧

toNote

作者偏向于数轴排序法

在 C++中,可以考虑创建预处理宏来替换 &&、||、==(不得已才这样做)

一般不这样做, 所以,toNote

在 Java 中,要理解 a==b 和 a.equals(b) 的差异

a==b:判断的是 a 和 b 是否引用了同一个对象,即比较的是地址

a.equals(b):判断这两个对象是否具有相同的值

一般来说,应该使用 a.equals(b) 这样的表达式